package com.deep.test.designpattern.proxy;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * <p>Description:</p>
 * Created with IDEA
 * author:hudepin
 * createTime:2018/5/22 13:34
 */
public class DpProxy {
    public static final String ln = "\r\n";


    public static Object newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces, DpInvocationHandler invocationHandler) {
        try {


            //1、动态生成源码文件
            String src = genrateSrc(interfaces,getProxyClass(invocationHandler));
            //2、java文件输出到磁盘
            String filePath = DpProxy.class.getResource("").getPath();
            System.out.println("filepath:" + filePath);
            File f = new File(filePath + "$Proxy1.java");
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();
            //3、把生成的java文件编译成classs文件
            JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null);
            Iterable i = standardJavaFileManager.getJavaFileObjects(f);
            JavaCompiler.CompilationTask task = javaCompiler.getTask(null, standardJavaFileManager, null, null, null, i);
            task.call();
            standardJavaFileManager.close();
            //4、编译生成的class文件加载到jvm
            Class proxyClass = classLoader.loadClass("$Proxy1");
            Constructor constructor = proxyClass.getConstructor(DpInvocationHandler.class);
            f.delete();
            return constructor.newInstance(invocationHandler);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    private static Class getProxyClass(DpInvocationHandler h) throws NoSuchMethodException, NoSuchFieldException {
        System.out.println(h.getClass());

        return h.getClass().getDeclaredField("target").getDeclaringClass();
    }
    private static String genrateSrc(Class<?>[] interfaces,Class<?> proxyClass) throws NoSuchMethodException {

        StringBuffer sb = new StringBuffer();
        sb.append("package com.deep.test.designpattern.proxy;" + ln);
        sb.append("import "+proxyClass.getName()+";" + ln);
        sb.append("import java.lang.reflect.Method;" + ln);
        sb.append("public class $Proxy1 implements " + interfaces[0].getName() + "{" + ln);

        sb.append("DpInvocationHandler h;" + ln);

        sb.append("public $Proxy1(DpInvocationHandler h) { " + ln);

        sb.append("this.h = h;");

        sb.append("}" + ln);


        for (Method m : interfaces[0].getMethods()) {
            sb.append("public " + m.getReturnType().getName() + " " + m.getName() + "() {" + ln);
            sb.append("try{" + ln);
            sb.append("Method m = " + interfaces[0].getName() + ".class.getMethod(\"" + m.getName() + "\",new Class[]{});" + ln);
            sb.append("this.h.invoke(this,m,null);" + ln);
            sb.append("}catch(Throwable e){" + ln);
            sb.append("e.printStackTrace();" + ln);
            sb.append("}");
            sb.append("}");
        }

        sb.append("}" + ln);

        return sb.toString();
    }
}
